//
//  DevicesManager.m
//  Portable Reader
//
//  Created by Chris Karr on 7/9/08.
//  Copyright 2008 Northwestern University. All rights reserved.
//

#import "DevicesManager.h"

#import <IOKit/usb/IOUSBLib.h>
#import <IOKit/IOCFPlugIn.h>

#import "iPhone.h"
#import "iPodClassic.h"
#import "SonyPRS505.h"

@implementation DevicesManager

- (NSArray *) devices
{
	mach_port_t masterPort;
    CFMutableDictionaryRef matchingDict;
	
    kern_return_t kr;
	
    kr = IOMasterPort (MACH_PORT_NULL, &masterPort);
    if (kr || !masterPort)
    {
        NSLog (@"ERR: Couldn't create a master I/O Kit port(%08x)", kr);
        return nil;
    }
	
    matchingDict = IOServiceMatching (kIOUSBDeviceClassName);
    if (!matchingDict)
    {
        NSLog (@"Couldn't create a USB matching dictionary");
        mach_port_deallocate(mach_task_self(), masterPort);
        return nil;
    }
	
	io_iterator_t iter;
	IOServiceGetMatchingServices (kIOMasterPortDefault, matchingDict, &iter);
	
	NSMutableArray * foundDevices = [NSMutableArray array];
	
	io_service_t usbDevice;
    while (usbDevice = IOIteratorNext (iter))
    {
		IOCFPlugInInterface	**plugInInterface = NULL;
		SInt32 score;
		
		//Create an intermediate plug-in
        kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
		
        if ((kIOReturnSuccess != kr) || !plugInInterface)
            printf("Unable to create a plug-in (%08x)\n", kr);
		
		IOUSBDeviceInterface182 **dev = NULL;
		
        //Now create the device interface
		HRESULT result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev);
		
        if (result || !dev)
            printf("Couldn't create a device interface (%08x)\n", (int) result);
		
		UInt16 vendor;
		UInt16 product;
		UInt16 release;
		
        //Check these values for confirmation
        kr = (*dev)->GetDeviceVendor(dev, &vendor);
        kr = (*dev)->GetDeviceProduct(dev, &product);
        kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
		
        kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
		
		UInt8 stringIndex;
        
		kr = (*dev)->USBGetProductStringIndex(dev, &stringIndex);
		
		IOUSBConfigurationDescriptorPtr desc;
		
        kr = (*dev)->GetConfigurationDescriptorPtr(dev, stringIndex, &desc);
		
		io_name_t deviceName;
		kr = IORegistryEntryGetName (usbDevice, deviceName);
		if (KERN_SUCCESS != kr)
		{
			NSLog (@"fail 0x%8x", kr);
			deviceName[0] = '\0';
		}
		
		Device * device = nil;
		
		if (vendor == 0x54c && product == 0x031e)		// Sony Portable Reader System 505
			device = [[SonyPRS505 alloc] init];
		else if (vendor == 0x5ac && product == 0x1290)	// Apple iPhone
			device = [[iPhone alloc] init];
		else if (vendor == 0x5ac && product == 0x120a)	// Apple iPod
		{
			device = [[iPodClassic alloc] init];
			device.name = [device.name stringByAppendingString:@" Nano"];
		}

		if (device != nil)
		{
			NSLog (@"%@", [NSString stringWithFormat:@"%@ (0x%x 0x%x 0x%x)", device.name, vendor, product, release]);
			[foundDevices addObject:device];
		}
		
        IOObjectRelease(usbDevice);
        (*plugInInterface)->Release(plugInInterface);
        (*dev)->Release(dev);
    }
	
    //Finished with master port
    mach_port_deallocate(mach_task_self(), masterPort);
    masterPort = 0;
	
	// [foundDevices sortUsingSelector:@selector(compare:)];

	return foundDevices;
}

- (void) refresh
{
	[[devices mutableChildNodes] removeAllObjects];
	[[lists mutableChildNodes] removeAllObjects];

	for (Device * device in [self devices])
	{
		NSMutableDictionary * item = [NSMutableDictionary dictionary];
		[item setValue:device.name forKey:@"name"];
		[item setObject:device.files forKey:@"files"];
		[item setValue:[NSNumber numberWithBool:NO] forKey:@"isGroup"];
		[item setValue:device forKey:@"device"];
		
		NSTreeNode * prs = [NSTreeNode treeNodeWithRepresentedObject:item];
	
		[[devices mutableChildNodes] addObject:prs];
	}
	
	[outline expandItem:[outline itemAtRow:1] expandChildren:NO];
	[outline expandItem:[outline itemAtRow:0] expandChildren:NO];
}	

- (void) awakeFromNib
{
	NSBrowserCell * cell = [column dataCell];
	[cell setFont:[NSFont systemFontOfSize:11.0]];
	[column setDataCell:cell];
	
	NSMutableDictionary * item = [NSMutableDictionary dictionary];
	[item setValue:@"MY DEVICES" forKey:@"name"];
	[item setValue:[NSNumber numberWithBool:YES] forKey:@"isGroup"];
	
	devices = [NSTreeNode treeNodeWithRepresentedObject:item];
	
	[tree addObject:devices];
	
	item = [NSMutableDictionary dictionary];
	[item setValue:@"MY LISTS" forKey:@"name"];
	[item setValue:[NSNumber numberWithBool:YES] forKey:@"isGroup"];
	
	lists = [NSTreeNode treeNodeWithRepresentedObject:item];
	
	[tree addObject:lists];
	
	[self refresh];
}


- (BOOL) outlineView:(NSOutlineView *) sender isGroupItem:(id) item 
{
	if ([[[[item representedObject] representedObject] objectForKey:@"isGroup"] boolValue])
		return YES;
	else
		return NO;
}

- (BOOL) outlineView:(NSOutlineView *) outlineView shouldSelectItem:(id) item
{
	return ![self outlineView:outlineView isGroupItem:item];
}
	
@end
